package com.xiaobaibai.security;

import com.xiaobaibai.security.common.HttpFailureHandler;
import com.xiaobaibai.security.common.OptionsRequestFilter;
import com.xiaobaibai.security.common.PropertiesInfo;
import com.xiaobaibai.security.common.TokenLogoutHandler;
import com.xiaobaibai.security.common.globalErrorHandler.SimpleAccessDeniedHandler;
import com.xiaobaibai.security.common.globalErrorHandler.SimpleAuthenticationEntryPoint;
import com.xiaobaibai.security.login.config.LoginConfig;
import com.xiaobaibai.security.login.config.No2LoginConfig;
import com.xiaobaibai.security.login.dao.LoginUserDetailService;
import com.xiaobaibai.security.login.filter.MyUsernamePasswordAuthenticationFilter;
import com.xiaobaibai.security.login.handler.MyLoginSuccessHandler;
import com.xiaobaibai.security.token.config.No2TokenConfig;
import com.xiaobaibai.security.token.config.No3TokenConfig;
import com.xiaobaibai.security.token.config.TokenConfig;
import com.xiaobaibai.security.token.handler.TokenSuccessHandler;
import com.xiaobaibai.security.token.provider.JwtAuthenticationProvider;
import com.xiaobaibai.server.token.ITokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import org.springframework.security.web.header.Header;
import org.springframework.security.web.header.writers.StaticHeadersWriter;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private OptionsRequestFilter optionsRequestFilter;

    @Autowired
    private ITokenService tokenService;

    @Autowired
    private LoginUserDetailService loginUserDetailService;

    @Autowired
    private PropertiesInfo propertiesInfo;

    @Autowired
    private SimpleAccessDeniedHandler simpleAccessDeniedHandler;

    @Autowired
    private SimpleAuthenticationEntryPoint simpleAuthenticationEntryPoint;

    @Bean//密码加密类(每次的盐都会不一样,但是都会匹配)
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public MyLoginSuccessHandler getLoginSuccessHandler(){
        return new MyLoginSuccessHandler();
    }

    @Bean
    public TokenSuccessHandler getTokenSuccessHandler(){
        return new TokenSuccessHandler();
    }

    @Bean
    public JwtAuthenticationProvider jwtAuthenticationProvider(){
        return new JwtAuthenticationProvider(tokenService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
//                .antMatchers("/**").permitAll()
                .antMatchers("/login","/error").permitAll()
                .antMatchers("/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .csrf().disable()//CRSF禁用，因为不使用session
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//禁用session
        .and()
        .formLogin().disable() //禁用form登录
        .cors()//支持跨域
        .and()
        .headers().addHeaderWriter(new StaticHeadersWriter(Arrays.asList(
        new Header("Access-control-Allow-Origin","*"),
        new Header("Access-Control-Expose-Headers","X-Token","New-Token"))))
        .and()
        .addFilterAfter(optionsRequestFilter, CorsFilter.class)
                //LoginConfig成功
                .apply(new LoginConfig<>()).loginSuccessHandler(getLoginSuccessHandler()).setUserDetailService(loginUserDetailService).setPasswordEncoder(passwordEncoder())
                //No2LoginConfig实验 webSecurityConfig  通过 跑的通
//                .apply(new No2LoginConfig()).loginSuccessHandler(getLoginSuccessHandler()).setUserDetailService(loginUserDetailService).setPasswordEncoder(passwordEncoder())
                .and()
                //TokenConfig里过滤器继承的类不符号场景,不可用
//                .apply(new TokenConfig<>()).tokenSuccessHandler(getTokenSuccessHandler()).setJwtAuthenticationProvider(jwtAuthenticationProvider())
                //NO2TokenConfig成功
                .apply(new No2TokenConfig<>()).tokenSuccessHandler(getTokenSuccessHandler()).setJwtAuthenticationProvider(jwtAuthenticationProvider()).setPropertiesInfo(propertiesInfo)
                //实验品种No3   实验通过  父类可用
//                .apply(new No3TokenConfig<>()).setAuthenticationSuccessHandler(getTokenSuccessHandler()).setJwtAuthenticationProvider(jwtAuthenticationProvider()).setPropertiesInfo(propertiesInfo)
                .and()
                .logout()
                .logoutUrl("/logout")//默认也是logout
                .addLogoutHandler(new TokenLogoutHandler())
                .logoutSuccessHandler(new TokenLogoutHandler())
        .and()
            .exceptionHandling()
                .accessDeniedHandler(simpleAccessDeniedHandler)
                .authenticationEntryPoint(simpleAuthenticationEntryPoint)
        ;
    }

    /**
     * 给重写UsernamePasswordFilter方法设置用的, 不想要了 就麻烦点吧
     */
//    @Bean
//    public AuthenticationManager authenticationManagerBean() throws Exception {
//        return super.authenticationManagerBean();
//    }


    //不明不白,这个不管了   todo  这个要加上  不管先...
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.authenticationProvider(daoAuthenticationProvider()).authenticationProvider(jwtAuthenticationProvider());
//    }
//
//    @Bean("daoAuthenticationProvider")
//    protected AuthenticationProvider daoAuthenticationProvider() throws Exception{
//        //这里会默认使用BCryptPasswordEncoder比对加密后的密码，注意要跟createUser时保持一致
//        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
//        daoProvider.setUserDetailsService(userDetailsService());
//        return daoProvider;
//    }
//
//    @Override
//    protected UserDetailsService userDetailsService() {
//        return new LoginUserDetailService();
//    }

}
